package com.borya.util.cipher;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;

import org.apache.commons.lang3.StringUtils;

import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.StreamUtil;


public class RSA {

	/**
	 * RSA加密，使用私钥进行加密
	 * @param content
	 * @param privateKey
	 * @param charset
	 * @return
	 * @throws AlipayApiException
	 */
	public static String rsaEncrypt(String content, String privateKey, String charset)
	        throws AlipayApiException
    {
        try
        {
//	            PublicKey pubKey = getPublicKeyFromX509("RSA", new ByteArrayInputStream(publicKey.getBytes()));
        	PrivateKey priKey = getPrivateKeyFromPKCS8("RSA", new ByteArrayInputStream(privateKey.getBytes()));
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(1, priKey);
            byte data[] = StringUtils.isEmpty(charset) ? content.getBytes() : content.getBytes(charset);
            int inputLen = data.length;
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offSet = 0;
            int i = 0;
            for(; inputLen - offSet > 0; offSet = ++i * 117)
            {
                byte cache[];
                if(inputLen - offSet > 117)
                    cache = cipher.doFinal(data, offSet, 117);
                else
                    cache = cipher.doFinal(data, offSet, inputLen - offSet);
                out.write(cache, 0, cache.length);
            }

            byte encryptedData[] = com.alipay.api.internal.util.codec.Base64.encodeBase64(out.toByteArray());
            out.close();
            return StringUtils.isEmpty(charset) ? new String(encryptedData) : new String(encryptedData, charset);
        }
        catch(Exception e)
        {
            throw new AlipayApiException((new StringBuilder()).append("EncryptContent = ").append(content).append(",charset = ").append(charset).toString(), e);
        }
    }

	/**
	 * RSA解密，使用公钥进行解密
	 * @param content
	 * @param publicKey
	 * @param charset
	 * @return
	 * @throws Exception
	 */
    public static String rsaDecrypt(String content, String publicKey, String charset)
        throws Exception
    {
        try
        {
//	            PrivateKey priKey = getPrivateKeyFromPKCS8("RSA", new ByteArrayInputStream(privateKey.getBytes()));
        	PublicKey pubKey = getPublicKeyFromX509("RSA", new ByteArrayInputStream(publicKey.getBytes()));
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(2, pubKey);
            byte encryptedData[] = StringUtils.isEmpty(charset) ? com.alipay.api.internal.util.codec.Base64.decodeBase64(content.getBytes()) : com.alipay.api.internal.util.codec.Base64.decodeBase64(content.getBytes(charset));
            int inputLen = encryptedData.length;
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offSet = 0;
            int i = 0;
            for(; inputLen - offSet > 0; offSet = ++i * 128)
            {
                byte cache[];
                if(inputLen - offSet > 128)
                    cache = cipher.doFinal(encryptedData, offSet, 128);
                else
                    cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
                out.write(cache, 0, cache.length);
            }

            byte decryptedData[] = out.toByteArray();
            out.close();
            return StringUtils.isEmpty(charset) ? new String(decryptedData) : new String(decryptedData, charset);
        }
        catch(Exception e)
        {
            throw new AlipayApiException((new StringBuilder()).append("EncodeContent = ").append(content).append(",charset = ").append(charset).toString(), e);
        }
    }
	
	
	
    public static PrivateKey getPrivateKeyFromPKCS8(String algorithm, InputStream ins)
            throws Exception
        {
            if(ins == null || StringUtils.isEmpty(algorithm))
            {
                return null;
            } else
            {
                KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
                byte encodedKey[] = StreamUtil.readText(ins).getBytes();
                encodedKey = com.alipay.api.internal.util.codec.Base64.decodeBase64(encodedKey);
                return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encodedKey));
            }
        }
	
	
    public static PublicKey getPublicKeyFromX509(String algorithm, InputStream ins)
            throws Exception
        {
            KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
            StringWriter writer = new StringWriter();
            StreamUtil.io(new InputStreamReader(ins), writer);
            byte encodedKey[] = writer.toString().getBytes();
            encodedKey = com.alipay.api.internal.util.codec.Base64.decodeBase64(encodedKey);
            return keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
        }
}
